﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using StatelyCompiler;
using System.IO;
using ObviousCode.Stately.Compiler.Parser;
using ObviousCode.Stately.Compiler.Templating;

namespace WindowsFormsApplication1
{
    public partial class _workflowCompiler : Form
    {
        public _workflowCompiler()
        {
            InitializeComponent();
        }

        private void _useDataContext_CheckedChanged(object sender, EventArgs e)
        {
            _dataContext.Enabled = _useDataContext.Checked;

            ValidateGoButtonState();
        }

        private void _text_TextChanged(object sender, EventArgs e)
        {
            ValidateGoButtonState();
        }

        private void ValidateGoButtonState()
        {
            _go.Enabled =
                _classname.Text.Length > 0 &&
                _namespace.Text.Length > 0 &&
                (!_useDataContext.Checked || _dataContext.Text.Length > 0);
        }

        private void _go_Click(object sender, EventArgs e)
        {
            CreateFiles();
        }

        private void CreateFiles()
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                ofd.Filter = "Workflow Maps (*.map)|*.map|All Files (*.*)|*.*";

                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    Start(ofd.FileName);
                }
            }
        }

        private void Start(string fileName)
        {
            Lexer lexer = new Lexer();

            List<Token> tokens;

            try
            {
                _output.AppendText("Lexing ... ");
                using (FileStream stream = File.OpenRead(fileName))
                {
                    tokens = lexer.Lex(stream);
                }
            }
            catch (Exception ex)
            {
                _output.AppendText("\r\nLexer failed.\r\n\r\n{0}".F(ex.Message));

                return;
            }

            _output.AppendText("Success ...");

            Parse(tokens, fileName);
        }

        private void Parse(List<Token> tokens, string sourceFile)
        {
            Exception exception = null;

            Parser parser = new Parser();

            parser.ExceptionOccured += (s, e) => exception = e.Item;

            _output.AppendText("\r\nParsing ... ");

            parser.Parse(tokens, (d) =>
            {
                if (exception != null)
                {
                    _output.AppendText("\r\n\r\nParse Error:{1}".F(exception.Message));
                }
                else
                {
                    _output.AppendText("Success ...");

                    WriteOutput(d, sourceFile);
                }
            });
        }

        private void WriteOutput(TransformData d, string sourceFile)
        {
            GeneratePartialFile(d, sourceFile);

            GenerateStubClassIfRequired(d, sourceFile);

            GenerateDataContextIfRequired(d, sourceFile);

            _output.AppendText("Generation completed.");
        }

        private void GenerateDataContextIfRequired(TransformData d, string sourceFile)
        {
            if (_useDataContext.Checked && _genDataContext.Checked)
            {
                try
                {
                    FileInfo source = new FileInfo(sourceFile);
                    string dataContextFileName = Path.Combine(source.DirectoryName, "{0}_stub.cs".F(d.DataContextName));

                    DataContextTemplate dataContextTemplate = new DataContextTemplate(d);

                    _output.AppendText("\r\n\r\nWriting Data Context Class ... ");

                    File.WriteAllText(dataContextFileName, dataContextTemplate.TransformText());

                    _output.AppendText("Success ...");
                }
                catch (Exception e)
                {
                    _output.AppendText("\r\n\rData Context File Creation Failed ...\r\n\r\n{0}".F(e.Message));
                }                
            }
        }

        private void GeneratePartialFile(TransformData d, string sourceFile)
        {
            try
            {
                _output.AppendText("\r\nWriting code ... ");

                d.ClassName = _classname.Text;
                d.Namespace = _namespace.Text;
                d.DataContextName = _useDataContext.Checked ? _dataContext.Text : string.Empty;

                FileInfo source = new FileInfo(sourceFile);
                string partialFileName = Path.Combine(source.DirectoryName, "__{0}.cs".F(d.ClassName));

                PartialClassTemplate partialTransform = new PartialClassTemplate(d);

                _output.AppendText("\r\nWriting Partial Class ... ");

                File.WriteAllText(partialFileName, partialTransform.TransformText());

                _output.AppendText("Success ...");
            }
            catch (Exception e)
            {
                _output.AppendText("\r\n\r\nPartial File Creation Failed ...\r\n\r\n{0}".F(e.Message));
            }
        }

        private void GenerateStubClassIfRequired(TransformData d, string sourceFile)
        {
            if (_generateStubClass.Checked)
            {
                try
                {
                    FileInfo source = new FileInfo(sourceFile);
                    string stubFileName = Path.Combine(source.DirectoryName, "{0}_stub.cs".F(d.ClassName));

                    StubClassTemplate stubTemplate = new StubClassTemplate(d);

                    _output.AppendText("\r\n\r\nWriting Stub Class ... ");

                    File.WriteAllText(stubFileName, stubTemplate.TransformText());

                    _output.AppendText("Success ...");
                }
                catch (Exception e)
                {
                    _output.AppendText("\r\n\rStub File Creation Failed ...\r\n\r\n{0}".F(e.Message));
                }
            }
        }

        private void _generateStubClass_CheckedChanged(object sender, EventArgs e)
        {
            ValidateGoButtonState();
        }
    }
}
